#include "../ds_types.h"
#include "dul_list.h"
#include <stdlib.h>
#include <string.h>

Status dullist_init(dul_list *dl)
{
	*dl = (dul_list) malloc(sizeof(dulnode));
	if(!(*dl)) exit(OVERFLOW);
	
	(*dl)->next = (*dl)->prior = *dl;
	return SUCCESS;
}

Status dullist_destroy(dul_list *dl)
{
	dulnode *q, *p = (*dl)->next;
	while(p != *dl){
		q = p->next;
		free(p->data);
		free(p);
		p = q;
	}
	
	free(*dl);
	return SUCCESS;
}

Status dullist_clear(dul_list dl)
{
	dulnode *q, *p = dl->next;
	while(p != dl){
		q = p->next;
		free(p->data);
		free(p);
		p = q;
	}
	
	dl->next = dl->prior = dl;
	return SUCCESS;
}

Bool dullist_empty(dul_list dl)
{
	return (dl->next == dl && dl->prior == dl);
}

size_t dullist_length(dul_list dl)
{
	size_t i = 0;
	dulnode *p = dl->next;
	while(p != dl){
		i++;
		p = p->next;
	}
	return i;
}

void *dulist_getelem(dul_list dl, size_t i)
{
	dulnode *p = dl->next;
	while(--i && p != dl) p = p->next;
	if(p == dl || i < 0) exit(ERROR);
	return p->data;
}

size_t dullist_locateelem(dul_list dl, const void *e,
		int cmp(const void *e1, const void *e2),
		size_t struct_size)
{
	dulnode *p = dl;
	size_t i = 1;
	while((p = p->next) != dl){
		if(cmp(p->data, e) == 0)
			return i;
		i++;
	}
	return 0;
}

Status dullist_insert(dul_list dl, size_t i, const void *e,
		size_t struct_size)
{
	dulnode *p = dl, *ne;
	ne = (dulnode *) malloc(sizeof(dulnode));
	if(!ne) exit(OVERFLOW);
	ne->data = malloc(struct_size);
	if(!ne->data) exit(OVERFLOW);
	memcpy(ne->data, e, struct_size);

	while(--i && p->next != dl) p = p->next;
	if(i != 0) return ERROR;
	
	ne->next = p->next;
	p->next = ne;
	ne->next->prior = ne;
	ne->prior = p;

	return SUCCESS;
}

Status dullist_delete(dul_list dl,size_t i, void *e, size_t struct_size)
{
	dulnode *p = dl->next;
	while(--i && p != dl) p = p->next;
	
	if(p == dl) return ERROR;

	memcpy(e, p->data, struct_size);

	p->prior->next = p->next;
	p->next->prior = p->prior;
	free(p->data);
	free(p);

	return SUCCESS;
}	

void dullist_traverse(dul_list dl, Bool visit(const void *))
{
	dulnode *p = dl;
	while((p = p->next) != dl)
		if(!visit(p->data))
			exit(ERROR);
}

void dullist_traverseback(dul_list dl, Bool visit(const void *))
{
	dulnode *p = dl;
	while((p = p->prior) != dl)
		if(!visit(p->data))
			exit(ERROR);
}
